#include "bsp_hrtimer.h"
#include "bsp_uart.h"

#define HRTIM_CLK (144000000U)
#define debug_printf(fmt, ...) UARTx_Printf(&huart3, fmt, ##__VA_ARGS__)


void bsp_HRTIM_Init(void)
{
    // HAL_HRTIM_WaveformCounterStart(&hhrtim1, HRTIM_TIMERID_MASTER | HRTIM_TIMERID_TIMER_A);//不能分开写，不同时打开会导致相位差
	// HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1 | HRTIM_OUTPUT_TA2);
//	HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TA1|HRTIM_OUTPUT_TA2); //通道打开
//	HAL_HRTIM_WaveformCounterStart(&hhrtim1, HRTIM_TIMERID_TIMER_A); //开启子定时器A
	
	HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TB1|HRTIM_OUTPUT_TB2); //通道打开
	HAL_HRTIM_WaveformOutputStart(&hhrtim1, HRTIM_OUTPUT_TE1|HRTIM_OUTPUT_TE2); //通道打开
	
}


double bsp_HRTimer_Get_Clk(uint32_t TimerIdx)
{
	double clk;
	switch (__HAL_HRTIM_GETCLOCKPRESCALER(&hhrtim1, TimerIdx))
	{
	case HRTIM_PRESCALERRATIO_MUL32:
		clk = 4608E6;
		break;
	case HRTIM_PRESCALERRATIO_MUL16:
		clk = 2304E6;
		break;
	case HRTIM_PRESCALERRATIO_MUL8:
		clk = 1152E6;
		break;
  	case HRTIM_PRESCALERRATIO_MUL4:
		clk = 576E6;
      	break;
	case HRTIM_PRESCALERRATIO_MUL2:
		clk = 288E6;
		break;
	case HRTIM_PRESCALERRATIO_DIV1:	
		clk = 144E6;
		break;
	case HRTIM_PRESCALERRATIO_DIV2:
		clk = 72E6;
		break;
	case HRTIM_PRESCALERRATIO_DIV4:
		clk = 36E6;
		break;
	default:
		break;
	}
	return clk;
}

inline float bsp_HRTIM_GetFerq(uint32_t TimerIdx)
{
	return (float)bsp_HRTimer_Get_Clk(TimerIdx)/__HAL_HRTIM_GETPERIOD(&hhrtim1, TimerIdx);
}

inline float bsp_HRTIM_GetDuty(uint32_t TimerIdx)
{
	return (float)__HAL_HRTIM_GETCOMPARE(&hhrtim1, TimerIdx, HRTIM_COMPAREUNIT_1)/__HAL_HRTIM_GETPERIOD(&hhrtim1, TimerIdx)*100;
}

/**
 * @brief 
 * @param TimerIdx 
 * @param duty [0,100]
 */
void bsp_HRTIM_SetDuty(uint32_t TimerIdx, uint8_t duty)
{
	uint16_t period = __HAL_HRTIM_GETPERIOD(&hhrtim1, TimerIdx);
	uint16_t compare = (uint16_t)(period * duty / 100.0 + 0.5);
	if (TimerIdx > 4) return;
	if (duty > 100) return;
	__HAL_HRTIM_SETCOMPARE(&hhrtim1, TimerIdx, HRTIM_COMPAREUNIT_1, compare);
}

/**
 * @brief set HRTimer frequnce
 * @param TimerIdx 
 * @param freq 
 */
void bsp_HRTIM_SetFerq(uint32_t TimerIdx, uint32_t freq)
{
	if (TimerIdx > 4) return;
	if (freq < bsp_HRTimer_Get_Clk(TimerIdx)/65535) return;
	float cur_duty = bsp_HRTIM_GetDuty(TimerIdx) + 0.5f;
	bsp_HRTIM_OutConfig(TimerIdx, freq, (uint8_t)cur_duty);
}

/**
 * @brief 
 * @param TimerIdx    @arg 0x5 for master timer
 *                    @arg 0x0 to 0x4 for timers A to E
 * @param freq 
 * @param duty 
 */
void bsp_HRTIM_OutConfig(uint32_t TimerIdx, uint32_t freq, uint8_t duty)
{
	// PERxR -- frequnce
	// CMP1xR -- duty
	
    // HAL_HRTIM_WaveformCompareConfig()
	// freq = F_clk / Period
	if (freq < bsp_HRTimer_Get_Clk(TimerIdx)/65535)
	{
		debug_printf("[error]Frequnce too small\r\n");
		return;
	}
	if (duty > 100)
	{
		debug_printf("[error]Duty too large\r\n");
		return;
	}
	if (TimerIdx > 4)
	{
		debug_printf("[error]TimerIdx too large\r\n");
		return;
	}
	uint16_t period = (uint16_t)(bsp_HRTimer_Get_Clk(TimerIdx) / freq + 0.5);
	uint16_t compare = (uint16_t)(period * duty / 100.0 + 0.5);
	__HAL_HRTIM_SETPERIOD(&hhrtim1, TimerIdx, period);
	__HAL_HRTIM_SETCOMPARE(&hhrtim1, TimerIdx, HRTIM_COMPAREUNIT_1, compare);
}

/**
 * @brief 
 * @param TimerIdx    @arg 0x5 for master timer
 *                    @arg 0x0 to 0x4 for timers A to E
 * @param deadtime    @arg ns [1, 56777]
 */
void bsp_HRTIM_SetDead(uint32_t TimerIdx, uint32_t deadtime)
{
	const float DF[8] = {HRTIM_CLK*1E-9*8, HRTIM_CLK*1E-9*4, HRTIM_CLK*1E-9*2, HRTIM_CLK*1E-9*1, 
						 HRTIM_CLK*1E-9/2, HRTIM_CLK*1E-9/4, HRTIM_CLK*1E-9/8, HRTIM_CLK*1E-9/16};
	const uint32_t CLK_CONFIG_TABLE[8] = 
	{HRTIM_TIMDEADTIME_PRESCALERRATIO_MUL8,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_MUL4,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_MUL2,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_DIV1,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_DIV2,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_DIV4,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_DIV8,
	 HRTIM_TIMDEADTIME_PRESCALERRATIO_DIV16};

	HRTIM_DeadTimeCfgTypeDef pDeadTimeCfg = {0};
	uint16_t DTValue;
	uint16_t clk_select;
	// 计算合适的分频
	for (clk_select = 0; clk_select < 8; clk_select++)
	{
		if (deadtime <= (int)(511.0f / DF[clk_select])) // max dead time 
		{
			break;
		}
	}
	if (clk_select >= 8)
	{
		// Error_Handler();
		debug_printf("[warning]DeadTime too large\r\n");
		return;
		// clk_select = 7;
	}
	// T * N = DT , N = DT / T = DT * DF;
	DTValue = (uint16_t) ((float)deadtime * DF[clk_select] + 0.5f);
	if (DTValue > 511) DTValue = 511;
	pDeadTimeCfg.Prescaler = CLK_CONFIG_TABLE[clk_select];
	pDeadTimeCfg.RisingValue = DTValue; // [0,511]
	pDeadTimeCfg.RisingSign = HRTIM_TIMDEADTIME_RISINGSIGN_POSITIVE;
	pDeadTimeCfg.RisingLock = HRTIM_TIMDEADTIME_RISINGLOCK_WRITE;
	pDeadTimeCfg.RisingSignLock = HRTIM_TIMDEADTIME_RISINGSIGNLOCK_WRITE;
	pDeadTimeCfg.FallingValue = DTValue;
	pDeadTimeCfg.FallingSign = HRTIM_TIMDEADTIME_FALLINGSIGN_POSITIVE;
	pDeadTimeCfg.FallingLock = HRTIM_TIMDEADTIME_FALLINGLOCK_WRITE;
	pDeadTimeCfg.FallingSignLock = HRTIM_TIMDEADTIME_FALLINGSIGNLOCK_WRITE;
	if (HAL_HRTIM_DeadTimeConfig(&hhrtim1, TimerIdx, &pDeadTimeCfg) != HAL_OK)
	{
		// Error_Handler();
		debug_printf("[error]HAL_HRTIM_DeadTimeConfig error\r\n");
	}

}


void dcdc_soft_start(uint32_t TimerIdx, uint32_t freq, uint8_t duty)
{

}

